function myVue(options) {
    this._init(options)
}

//模板方法模式吧？
myVue.prototype._init = function (options) {
    this.$options = options
    this.$el = document.querySelector(options.el)
    this.$data = options.data
    this.$methods = options.methods
    //理解这个binding很重要
    this._binding = {}
    this._observe(this.$data)
    this._compile(this.$el)
}
myVue.prototype._observe = function (obj) {
    var _this = this;
    Object.keys(obj).forEach(function (key) {
        if (obj.hasOwnProperty(key)) {
            // number
            _this._binding[key] = {
                _directives: []
            };
            console.log(_this._binding, key, _this._binding[key])
            var value = obj[key];
            if (typeof value === 'object') {
                _this._observe(value);
            }
            var binding = _this._binding[key];
            //number
            Object.defineProperty(_this.$data, key, {
                enumerable: true,
                configurable: true,
                get: function () {
                    console.log(`${key}获取${value}`);
                    return value;
                },
                set: function (newVal) {
                    console.log(`${key}更新${newVal}`);
                    if (value !== newVal) {
                        //??? 为啥是value呢？ 用obj【key]会进入死循环
                        // obj[key] = newVal;
                        //你要理解这个defineproperty的用法  value的用法 value改变 那么obj【key]就会被改变 
                        value = newVal
                        //存储了与dom对应的关系 这个是精华所在吧 也是我之前一直不能够理解的地方
                        binding._directives.forEach(function (item) {
                            //更新dom
                            item.update();
                        })
                    }
                }
            })
        }
    })
}


myVue.prototype._compile = function (root) {
    var _this = this
    var nodes = root.children

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i]
        if (node.children.length) {
            this._compile(node)
        }

        if (node.hasAttribute('v-click')) {
            node.onclick = (function (i) {
                var attrVal = nodes[i].getAttribute('v-click')
                return _this.$methods[attrVal].bind(_this.$data)
            })(i)
        }

        if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) {
            var attrVal = node.getAttribute('v-model');
            console.log('attval', attrVal)

            //dom变化通知到数据变化
            node.addEventListener('input', (function (key, attrVal) {
                //number
                _this._binding[attrVal]._directives.push(new Watcher('input', node, _this, attrVal, 'value'))

                return function () {
                    console.log('attval', attrVal)
                    console.log('nodes[key].value', nodes[key].value, attrVal)
                    _this.$data[attrVal] = nodes[key].value
                    console.log('_this.$data[attrVal]', _this.$data[attrVal])
                }
            })(i, attrVal))
        }

        if (node.hasAttribute('v-bind')) {
            var attrVal = node.getAttribute('v-bind')
            _this._binding[attrVal]._directives.push(new Watcher('text', node, _this, attrVal, 'innerHTML'))
        }
    }
}
function Watcher(name, el, vm, exp, attr) {
    this.name = name
    this.el = el
    this.vm = vm
    this.exp = exp
    this.attr = attr
    this.update()
}

Watcher.prototype.update = function () {
    this.el[this.attr] = this.vm.$data[this.exp]
}


